package com.nanyang.tms.mongo.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.aggregation.MatchOperation;
import org.springframework.data.mongodb.core.aggregation.ProjectionOperation;
import org.springframework.data.mongodb.core.aggregation.SkipOperation;
import org.springframework.data.mongodb.core.aggregation.UnwindOperation;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Repository;

import com.nanyang.common.core.domain.DataImportDomain;
import com.nanyang.tms.domain.dataimport.DataImportDO;
import com.nanyang.tms.domain.dataimport.DataImportLineQuery;
import com.nanyang.tms.domain.dataimport.DataImportLineVO;
import com.nanyang.tms.domain.dataimport.DataImportQuery;
import com.nanyang.tms.domain.dataimport.DataImportVO;
import com.nanyang.tms.mongo.DataImportDao;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
@Repository
public   class DataImportDaoImpl implements DataImportDao{
	    @Autowired
	    private MongoTemplate mongoTemplate;  
        @Override
        public DataImportDO insertDataImport(DataImportDO dataImportDO) {
        	return mongoTemplate.save(dataImportDO);
        }
         @Override
        public void updateDataImport(DataImportDO dataImportDO) {
        	 Query query = new Query();
             query.addCriteria(Criteria.where("id").is(dataImportDO.getId()));
             Update update = new Update();
             if(StringUtils.isNotEmpty(dataImportDO.getResult())){
            	 update.set("result", dataImportDO.getResult());
             }
             if(ObjectUtils.isNotEmpty(dataImportDO.getFailNum())){
            	 update.set("failNum", dataImportDO.getFailNum());
             }
             if(ObjectUtils.isNotEmpty(dataImportDO.getSuccessNum())){
            	 update.set("successNum", dataImportDO.getSuccessNum());
             }
             if(ObjectUtils.isNotEmpty(dataImportDO.getTotalNum())){
            	 update.set("totalNum", dataImportDO.getTotalNum());
             }
             if(ObjectUtils.isNotEmpty(dataImportDO.getStatus())){
            	 update.set("status", dataImportDO.getStatus());
             }
             if(CollectionUtils.isNotEmpty(dataImportDO.getSuccessLines())){
            	 update.push("successLines").each( dataImportDO.getSuccessLines());
             }
             if(CollectionUtils.isNotEmpty(dataImportDO.getFailLines())){
            	 update.push("failLines").each( dataImportDO.getFailLines());
             }
             
             mongoTemplate.updateFirst(query, update, DataImportDO.class);
        }
		@Override
		public List<DataImportVO> listDataImport(DataImportQuery dataImportQuery) {
			 Criteria criteria = new Criteria();
			 criteria.and("companyCode").is(dataImportQuery.getCompanyCode());
			 criteria.and("serviceType").is(dataImportQuery.getServiceType());
             if(ObjectUtils.isNotEmpty(dataImportQuery.getStatus())){
            	 criteria.and("status").is(dataImportQuery.getStatus());
             }
			 Query query = new Query();
             query.addCriteria(criteria);
             query.fields().exclude("successLines");
             query.fields().exclude("failLines");
             Sort sort = Sort.by(Sort.Direction.DESC, "gmtCreate");
             Pageable pageable = PageRequest.of(dataImportQuery.getPageIndex()-1,dataImportQuery.getPageSize(),sort);
             return mongoTemplate.find(query.with(pageable), DataImportVO.class,StrUtil.lowerFirst(DataImportDO.class.getSimpleName()));
		}
		@Override
		public List<DataImportLineVO> listDataImportLine(DataImportLineQuery dataImportLineQuery) {
			
			List<AggregationOperation> commonOperations = new ArrayList<>();
			MatchOperation match = Aggregation.match(Criteria.where("id").is(dataImportLineQuery.getId()).and("companyCode").is(dataImportLineQuery.getCompanyCode()));
			commonOperations.add(match);
			
			StringBuilder dataNode = new StringBuilder();
			if(dataImportLineQuery.getStatus().equals("success")){
				dataNode.append("successLines");
				
			}else{
				dataNode.append("failLines");
			}
			ProjectionOperation project = Aggregation.project(dataNode.toString());
			commonOperations.add(project);
			UnwindOperation unwind = Aggregation.unwind(dataNode.toString());
			commonOperations.add(unwind);
	        List<AggregationOperation> pageOperations = new ArrayList<>(commonOperations);
			 pageOperations.add(Aggregation.skip(dataImportLineQuery.getStartRow()));
			 pageOperations.add(Aggregation.limit(dataImportLineQuery.getPageSize()));
			Aggregation aggregation = Aggregation.newAggregation(pageOperations);
			AggregationResults<JSONObject> aggregateForecastInfo = mongoTemplate.aggregate(aggregation, DataImportDO.class,  JSONObject.class);
			List<JSONObject> mappedResults = aggregateForecastInfo.getMappedResults();
			List<DataImportLineVO> result = mappedResults.stream().map(x -> JSONUtil.toBean(x.getJSONObject(dataNode.toString()), DataImportLineVO.class)).collect(Collectors.toList());
			return  result;
		}
		@Override
		public long countDataImport(DataImportQuery dataImportQuery) {
			 Criteria criteria = new Criteria();
			 criteria.and("companyCode").is(dataImportQuery.getCompanyCode());
			 criteria.and("serviceType").is(dataImportQuery.getServiceType());
			    if(ObjectUtils.isNotEmpty(dataImportQuery.getStatus())){
	            	 criteria.and("status").is(dataImportQuery.getStatus());
	             }
			 Query query = new Query();
             query.addCriteria(criteria);
			return mongoTemplate.count(query, DataImportDO.class);
		}
		@Override
		public long countDataImportLine(DataImportLineQuery dataImportLineQuery) {
			List<AggregationOperation> commonOperations = new ArrayList<>();
			MatchOperation match = Aggregation.match(Criteria.where("id").is(dataImportLineQuery.getId()).and("companyCode").is(dataImportLineQuery.getCompanyCode()));
			commonOperations.add(match);
			String dataNode="";
			if(dataImportLineQuery.getStatus().equals("success")){
				dataNode="successLines";
				
			}else{
				dataNode="failLines";
			}
			ProjectionOperation project = Aggregation.project(dataNode);
			commonOperations.add(project);
			UnwindOperation unwind = Aggregation.unwind(dataNode);
			commonOperations.add(unwind);
			Aggregation aggregation = Aggregation.newAggregation(commonOperations);
			return mongoTemplate.aggregate(aggregation, DataImportDO.class,  DataImportLineVO.class).getMappedResults().size();
		}
}
